Repository navigation
refactor(desktop): cleaner, compact inline agent/port sections in v2 sidebar - #5426
Conversation
- Restyle port and agent chips as neutral Linear/Notion-style tags (bg-muted, 11px text, mono tabular port numbers) - Split ports and agents into separate collapsible sections with per-section persisted collapse state (workspaceId:sectionKey) - Hide section chevron until hover; align chips with the summary label - New DashboardSidebarChipStrip: one row while chips fit, two-row grid on overflow, then horizontal scroll two rows deep - Move per-port actions (open in browser, close) from hover icons into a right-click context menu so pills never resize on hover
…ver ⋮ menu Primary click on a port pill now opens the port (per the Settings → Links → Ports preference); remote ports fall back to opening the workspace. A vertical ellipsis fades in on hover (opacity only, so the pill never resizes) with Open in Browser / Go to Workspace / Close Port.
|
Ready to review this PR? Stage has broken it down into 5 individual chapters for you: Chapters generated by Stage for commit 2fc582f on Jul 3, 2026 12:35am UTC. |
📝 WalkthroughWalkthroughThis PR adds an adaptive sidebar chip strip, uses it in port and agent rows, refactors port badge actions into a dropdown, and changes workspace details collapse state from workspace-level to section-level keys. ChangesSidebar chip strip and port actions
Estimated code review effort: 3 (Moderate) | ~25 minutes Workspace details per-section collapse
Estimated code review effort: 2 (Simple) | ~15 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR refactors the v2 dashboard sidebar's inline port and agent UI — replacing tinted
Confidence Score: 4/5Safe to merge for the visual and interaction improvements; the chip layout revert from two-row back to one-row may get stuck once chips are removed, which is worth fixing before shipping to users with many ports. The new DashboardSidebarChipStrip has a measurement flaw: CSS Grid stretches narrower chips to their column max-content width in two-row mode, inflating offsetWidth values. The summed needed width stays above available even after enough chips are removed, so the layout never reverts to a single row once the threshold is crossed. The remaining concerns are non-blocking quality issues. DashboardSidebarChipStrip.tsx — the measurement loop and the grid class applied when isTwoRows is true.
|
| Filename | Overview |
|---|---|
| apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarChipStrip/DashboardSidebarChipStrip.tsx | New component for adaptive 1-row/2-row chip layout; grid mode inflates offsetWidth for narrower chips sharing a column, preventing revert to single-row when chips are removed |
| apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarPortsList/components/DashboardSidebarPortBadge/DashboardSidebarPortBadge.tsx | Reworked port pill: primary click opens port/workspace, hover-revealed ⋮ dropdown for Open in Browser / Go to Workspace / Close Port with kill-pending spinner |
| apps/desktop/src/renderer/stores/workspace-details/store.ts | Changed persist key to composite workspace:section keys; no migration added so old collapsedWorkspaceIds data lingers in localStorage |
| apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceDetails/DashboardSidebarWorkspaceDetails.tsx | Splits combined toggle into per-section toggles; subscribes to full collapsedSectionKeys object causing all workspace panels to re-render on any toggle |
| apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceDetails/components/DashboardSidebarWorkspaceDetailsToggle/DashboardSidebarWorkspaceDetailsToggle.tsx | Section chevron hidden until hover via opacity transition; straightforward visibility tweak |
| apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspacePortsRow/DashboardSidebarWorkspacePortsRow.tsx | Swaps flex-wrap div for DashboardSidebarChipStrip with updated alignment padding |
| apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceAgentsRow/DashboardSidebarWorkspaceAgentsRow.tsx | Swaps flex-wrap div for DashboardSidebarChipStrip with matching padding adjustment |
| apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceAgentsRow/components/DashboardSidebarWorkspaceAgentBadge/DashboardSidebarWorkspaceAgentBadge.tsx | Restyled to neutral muted tag from primary tinted chip; smaller icon sizes match new design language |
| apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarPortsList/components/DashboardSidebarPortGroup/DashboardSidebarPortGroup.tsx | Replaced hardcoded 2-row OverflowFadeContainer with DashboardSidebarChipStrip for adaptive layout |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[DashboardSidebarWorkspaceDetails] -->|per section| B[DashboardSidebarWorkspaceDetailsToggle]
A -->|ports section| C[DashboardSidebarWorkspacePortsRow]
A -->|agents section| D[DashboardSidebarWorkspaceAgentsRow]
C --> E[DashboardSidebarChipStrip]
D --> E
E -->|measure on render + resize| F{chips fit in 1 row?}
F -->|yes| G[flex row]
F -->|no| H[grid-rows-2 grid-flow-col]
G --> I[OverflowFadeContainer horizontal scroll]
H --> I
C --> J[DashboardSidebarPortBadge]
J --> K[Primary button: open port / workspace]
J --> L[Dropdown: Open in Browser / Go to Workspace / Close Port]
A -->|collapse state| M[useWorkspaceDetailsStore collapsedSectionKeys]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[DashboardSidebarWorkspaceDetails] -->|per section| B[DashboardSidebarWorkspaceDetailsToggle]
A -->|ports section| C[DashboardSidebarWorkspacePortsRow]
A -->|agents section| D[DashboardSidebarWorkspaceAgentsRow]
C --> E[DashboardSidebarChipStrip]
D --> E
E -->|measure on render + resize| F{chips fit in 1 row?}
F -->|yes| G[flex row]
F -->|no| H[grid-rows-2 grid-flow-col]
G --> I[OverflowFadeContainer horizontal scroll]
H --> I
C --> J[DashboardSidebarPortBadge]
J --> K[Primary button: open port / workspace]
J --> L[Dropdown: Open in Browser / Go to Workspace / Close Port]
A -->|collapse state| M[useWorkspaceDetailsStore collapsedSectionKeys]
Comments Outside Diff (1)
-
apps/desktop/src/renderer/stores/workspace-details/store.ts, line 36-44 (link)Stale
collapsedWorkspaceIdskey accumulates inlocalStoragewithout cleanupThe store is persisted under the same
"workspace-details-store"name, but the top-level key changed fromcollapsedWorkspaceIdstocollapsedSectionKeys. Without a Zustandmigratefunction and a bumpedversion, the old key is silently ignored but remains inlocalStorageindefinitely. Adding a migration that drops the old key would keep storage clean.Prompt To Fix With AI
This is a comment left during a code review. Path: apps/desktop/src/renderer/stores/workspace-details/store.ts Line: 36-44 Comment: **Stale `collapsedWorkspaceIds` key accumulates in `localStorage` without cleanup** The store is persisted under the same `"workspace-details-store"` name, but the top-level key changed from `collapsedWorkspaceIds` to `collapsedSectionKeys`. Without a Zustand `migrate` function and a bumped `version`, the old key is silently ignored but remains in `localStorage` indefinitely. Adding a migration that drops the old key would keep storage clean. How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 3
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarChipStrip/DashboardSidebarChipStrip.tsx:44-48
**Grid mode inflates chip widths, blocking revert to single row**
When `isTwoRows` is `true`, the container renders as a CSS Grid with `auto-cols-max grid-flow-col`. Grid items stretch to fill their column area by default (`justify-self: stretch`), so a narrow chip sharing a column with a wider chip will report `offsetWidth` equal to the wider chip's width. The `measure` function then sums these inflated values and consistently decides `needed > available`, keeping the layout in two-row mode even after enough chips are removed to fit in a single row.
The fix is to add `justify-items-start` to the grid variant so chips only occupy their natural content width, keeping `offsetWidth` accurate in both layout modes. For example, `isTwoRows ? "grid auto-cols-max grid-flow-col grid-rows-2 justify-items-start" : "flex"`.
### Issue 2 of 3
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceDetails/DashboardSidebarWorkspaceDetails.tsx:46-48
**All workspace detail panels re-render on any section toggle**
The selector returns the entire `collapsedSectionKeys` object, which is replaced with a new object reference on every `setExpanded` call. Every mounted `DashboardSidebarWorkspaceDetails` instance (one per visible workspace) will re-render whenever any workspace's section is toggled. Narrowing the selector to only the keys this workspace actually needs — `${workspaceId}:ports` and `${workspaceId}:agents` — would scope the subscription correctly.
### Issue 3 of 3
apps/desktop/src/renderer/stores/workspace-details/store.ts:36-44
**Stale `collapsedWorkspaceIds` key accumulates in `localStorage` without cleanup**
The store is persisted under the same `"workspace-details-store"` name, but the top-level key changed from `collapsedWorkspaceIds` to `collapsedSectionKeys`. Without a Zustand `migrate` function and a bumped `version`, the old key is silently ignored but remains in `localStorage` indefinitely. Adding a migration that drops the old key would keep storage clean.
Reviews (1): Last reviewed commit: "feat(desktop): split port menu open acti..." | Re-trigger Greptile
| let needed = -CHIP_GAP_PX; | ||
| for (const child of Array.from(node.children)) { | ||
| needed += (child as HTMLElement).offsetWidth + CHIP_GAP_PX; | ||
| } | ||
| setIsTwoRows(needed > available); |
There was a problem hiding this comment.
Grid mode inflates chip widths, blocking revert to single row
When isTwoRows is true, the container renders as a CSS Grid with auto-cols-max grid-flow-col. Grid items stretch to fill their column area by default (justify-self: stretch), so a narrow chip sharing a column with a wider chip will report offsetWidth equal to the wider chip's width. The measure function then sums these inflated values and consistently decides needed > available, keeping the layout in two-row mode even after enough chips are removed to fit in a single row.
The fix is to add justify-items-start to the grid variant so chips only occupy their natural content width, keeping offsetWidth accurate in both layout modes. For example, isTwoRows ? "grid auto-cols-max grid-flow-col grid-rows-2 justify-items-start" : "flex".
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarChipStrip/DashboardSidebarChipStrip.tsx
Line: 44-48
Comment:
**Grid mode inflates chip widths, blocking revert to single row**
When `isTwoRows` is `true`, the container renders as a CSS Grid with `auto-cols-max grid-flow-col`. Grid items stretch to fill their column area by default (`justify-self: stretch`), so a narrow chip sharing a column with a wider chip will report `offsetWidth` equal to the wider chip's width. The `measure` function then sums these inflated values and consistently decides `needed > available`, keeping the layout in two-row mode even after enough chips are removed to fit in a single row.
The fix is to add `justify-items-start` to the grid variant so chips only occupy their natural content width, keeping `offsetWidth` accurate in both layout modes. For example, `isTwoRows ? "grid auto-cols-max grid-flow-col grid-rows-2 justify-items-start" : "flex"`.
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| const collapsedSectionKeys = useWorkspaceDetailsStore( | ||
| (state) => state.collapsedSectionKeys, | ||
| ); |
There was a problem hiding this comment.
All workspace detail panels re-render on any section toggle
The selector returns the entire collapsedSectionKeys object, which is replaced with a new object reference on every setExpanded call. Every mounted DashboardSidebarWorkspaceDetails instance (one per visible workspace) will re-render whenever any workspace's section is toggled. Narrowing the selector to only the keys this workspace actually needs — ${workspaceId}:ports and ${workspaceId}:agents — would scope the subscription correctly.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceDetails/DashboardSidebarWorkspaceDetails.tsx
Line: 46-48
Comment:
**All workspace detail panels re-render on any section toggle**
The selector returns the entire `collapsedSectionKeys` object, which is replaced with a new object reference on every `setExpanded` call. Every mounted `DashboardSidebarWorkspaceDetails` instance (one per visible workspace) will re-render whenever any workspace's section is toggled. Narrowing the selector to only the keys this workspace actually needs — `${workspaceId}:ports` and `${workspaceId}:agents` — would scope the subscription correctly.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceAgentsRow/DashboardSidebarWorkspaceAgentsRow.tsx (1)
2-2: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRelative import instead of path alias.
This imports
DashboardSidebarChipStripvia a relative path (../../../../components/DashboardSidebarChipStrip) rather than the configuredtsconfig.jsonpath alias. As per path instructions,apps/desktop/src/**/*.{ts,tsx}: "When possible, use the path aliases defined intsconfig.jsoninstead of relative imports."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceAgentsRow/DashboardSidebarWorkspaceAgentsRow.tsx` at line 2, The import in DashboardSidebarWorkspaceAgentsRow is using a deep relative path instead of the configured tsconfig alias. Update the DashboardSidebarChipStrip import to use the appropriate path alias used throughout apps/desktop/src/**/*.{ts,tsx} rather than "../../../../components/DashboardSidebarChipStrip", keeping the rest of DashboardSidebarWorkspaceAgentsRow unchanged.Source: Path instructions
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspacePortsRow/DashboardSidebarWorkspacePortsRow.tsx (2)
2-2: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRelative import instead of path alias.
Same as in
DashboardSidebarWorkspaceAgentsRow.tsx— relative import used instead of thetsconfig.jsonpath alias. As per path instructions,apps/desktop/src/**/*.{ts,tsx}: "When possible, use the path aliases defined intsconfig.jsoninstead of relative imports."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspacePortsRow/DashboardSidebarWorkspacePortsRow.tsx` at line 2, The import in DashboardSidebarWorkspacePortsRow should use the tsconfig path alias instead of a deep relative path, matching the import style used in DashboardSidebarWorkspaceAgentsRow. Update the DashboardSidebarChipStrip import to reference the alias-based path so the component location is resolved consistently across apps/desktop/src/**/*.{ts,tsx} and avoid relative traversal from DashboardSidebarWorkspacePortsRow.Source: Path instructions
22-32: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueSame padding-drop and duplicate
pr-2/pl-11/pl-9logic as the agents row.This mirrors
DashboardSidebarWorkspaceAgentsRow.tsx'scn("pr-2", isInSection ? "pl-11" : "pl-9")verbatim. Consider extracting this into a shared constant/helper (e.g. agetChipRowClassName(isInSection)util) co-located nearDashboardSidebarChipStrip, since both rows share the identical alignment comment and logic.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspacePortsRow/DashboardSidebarWorkspacePortsRow.tsx` around lines 22 - 32, The padding/alignment logic in DashboardSidebarWorkspacePortsRow duplicates the same `DashboardSidebarChipStrip` class setup used by the agents row, so extract the shared `cn("pr-2", isInSection ? "pl-11" : "pl-9")` behavior into a reusable helper or constant near `DashboardSidebarChipStrip` (for example a `getChipRowClassName(isInSection)` utility). Update both DashboardSidebarWorkspacePortsRow and DashboardSidebarWorkspaceAgentsRow to call the shared symbol so the padding-drop behavior stays consistent in one place.apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarPortsList/components/DashboardSidebarPortBadge/DashboardSidebarPortBadge.tsx (1)
89-132: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valuePrimary button isn't disabled during
openUrlmutation, only the dropdown item is.The dropdown's "Open in Browser" item is disabled via
disabled={openUrl.isPending}(line 161), but the primary button (which invokes the samehandleOpenInBrowserwhencanOpenInBrowser) is only guarded bydisabled={isPending}(kill-pending), notopenUrl.isPending. The early return insidehandleOpenInBrowserprevents a duplicate mutation, but the button remains visually clickable/enabled while the external URL request is in flight.💡 Optional fix for visual consistency
<button type="button" onClick={handlePrimaryClick} - disabled={isPending} - aria-busy={isPending} + disabled={isPending || (canOpenInBrowser && openUrl.isPending)} + aria-busy={isPending || (canOpenInBrowser && openUrl.isPending)} className="flex min-w-0 items-center gap-1 rounded-l py-0.5 pl-1.5 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" >🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarPortsList/components/DashboardSidebarPortBadge/DashboardSidebarPortBadge.tsx` around lines 89 - 132, The primary port badge button in DashboardSidebarPortBadge should also reflect the openUrl mutation state, not just the kill-pending state. Update the button’s disabled/aria-busy logic and any related styling in DashboardSidebarPortBadge so it uses openUrl.isPending alongside isPending, matching the existing dropdown item behavior and preventing the button from appearing interactive while handleOpenInBrowser is already running.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/desktop/src/renderer/stores/workspace-details/store.ts`:
- Around line 5-39: Persisted workspace-details state was renamed from
collapsedWorkspaceIds to collapsedSectionKeys, so existing
workspace-details-store data will not load correctly. In
useWorkspaceDetailsStore’s persist config, either add version: 1 to
intentionally reset stored state, or add a migrate handler that converts old
collapsedWorkspaceIds entries into the new per-section collapsedSectionKeys
shape before hydration.
---
Nitpick comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarPortsList/components/DashboardSidebarPortBadge/DashboardSidebarPortBadge.tsx`:
- Around line 89-132: The primary port badge button in DashboardSidebarPortBadge
should also reflect the openUrl mutation state, not just the kill-pending state.
Update the button’s disabled/aria-busy logic and any related styling in
DashboardSidebarPortBadge so it uses openUrl.isPending alongside isPending,
matching the existing dropdown item behavior and preventing the button from
appearing interactive while handleOpenInBrowser is already running.
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceAgentsRow/DashboardSidebarWorkspaceAgentsRow.tsx`:
- Line 2: The import in DashboardSidebarWorkspaceAgentsRow is using a deep
relative path instead of the configured tsconfig alias. Update the
DashboardSidebarChipStrip import to use the appropriate path alias used
throughout apps/desktop/src/**/*.{ts,tsx} rather than
"../../../../components/DashboardSidebarChipStrip", keeping the rest of
DashboardSidebarWorkspaceAgentsRow unchanged.
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspacePortsRow/DashboardSidebarWorkspacePortsRow.tsx`:
- Line 2: The import in DashboardSidebarWorkspacePortsRow should use the
tsconfig path alias instead of a deep relative path, matching the import style
used in DashboardSidebarWorkspaceAgentsRow. Update the DashboardSidebarChipStrip
import to reference the alias-based path so the component location is resolved
consistently across apps/desktop/src/**/*.{ts,tsx} and avoid relative traversal
from DashboardSidebarWorkspacePortsRow.
- Around line 22-32: The padding/alignment logic in
DashboardSidebarWorkspacePortsRow duplicates the same
`DashboardSidebarChipStrip` class setup used by the agents row, so extract the
shared `cn("pr-2", isInSection ? "pl-11" : "pl-9")` behavior into a reusable
helper or constant near `DashboardSidebarChipStrip` (for example a
`getChipRowClassName(isInSection)` utility). Update both
DashboardSidebarWorkspacePortsRow and DashboardSidebarWorkspaceAgentsRow to call
the shared symbol so the padding-drop behavior stays consistent in one place.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 36f4984a-9805-4b23-b479-739fb74ff0c5
📒 Files selected for processing (10)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarChipStrip/DashboardSidebarChipStrip.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarChipStrip/index.tsapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarPortsList/components/DashboardSidebarPortBadge/DashboardSidebarPortBadge.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarPortsList/components/DashboardSidebarPortGroup/DashboardSidebarPortGroup.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceAgentsRow/DashboardSidebarWorkspaceAgentsRow.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceAgentsRow/components/DashboardSidebarWorkspaceAgentBadge/DashboardSidebarWorkspaceAgentBadge.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceDetails/DashboardSidebarWorkspaceDetails.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceDetails/components/DashboardSidebarWorkspaceDetailsToggle/DashboardSidebarWorkspaceDetailsToggle.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspacePortsRow/DashboardSidebarWorkspacePortsRow.tsxapps/desktop/src/renderer/stores/workspace-details/store.ts
There was a problem hiding this comment.
2 issues found and verified against the latest diff
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
- justify-items-start in 2-row grid so stretched chips don't inflate measured widths and lock the strip in two-row mode (greptile P1) - narrow the collapsed-sections selector to this workspace's keys so toggling one workspace doesn't re-render all panels (greptile P2) - migrate persisted v0 collapsedWorkspaceIds into per-section keys instead of dropping users' collapse state (coderabbit)
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
Summary
bg-primarychips.Why / Context
The inline agent/port UI read as loud colored CTAs, pills were oversized with phantom trailing space (invisible hover icons reserved ~28px each), rows misaligned with the section toggle, and hover made pills grow and push their neighbors.
How It Works
DashboardSidebarPortBadge,DashboardSidebarWorkspaceAgentBadge):bg-muted/60neutral tags attext-[11px]with mono tabular port numbers; status color is reserved for the agent status dot.DashboardSidebarWorkspaceDetails): each detail section renders its own toggle row;useWorkspaceDetailsStorenow keys collapse state by${workspaceId}:${sectionKey}(previously per-workspace); a persist migration (v0 → v1) expands each old per-workspace collapsed flag into both section keys.DashboardSidebarChipStrip): measures chips' natural widths against the container (every render + ResizeObserver) and toggles between a flex row and agrid-rows-2column-flow grid, wrapped inOverflowFadeContainerfor the scroll fade. Pure-CSS child growth intentionally doesn't re-measure, so hover can't flip the layout.Manual QA Checklist
Testing
bun run typecheckbunx biome check .(rootbun run lintadditionally shells out to ripgrep, which isn't installed on this machine; Biome itself is clean)Design Decisions
DashboardSidebarChipStripcompares natural chip widths to the container width.Known Limitations
Follow-ups
WorkspaceSidebarports UI intentionally untouched (v1 is sunset).Summary by cubic
Refactors the v2 sidebar ports/agents UI with compact neutral tags, per-section collapsible groups, and a measured two-row chip layout. Port pills open per preference on click; the menu separates External vs Superset in‑app open, and existing collapse state is preserved.
New Features
DashboardSidebarChipStrip: single row, then two‑row grid on overflow, then horizontal scroll without hover shifts.Refactors
DashboardSidebarChipStripto measure chip widths and choose 1‑row/2‑row/scroll; bottom “Ports” list uses the same layout. Grid uses justify‑items‑start to avoid stretched chips inflating measurements.${workspaceId}:${sectionKey}with a migration from v0collapsedWorkspaceIdsto per‑section keys (existing collapsed workspaces map to collapsed Ports and Agents).Written for commit 2fc582f. Summary will update on new commits.
Summary by CodeRabbit
New Features
Bug Fixes / UX Improvements
Style